package com.tbit.uqbike.service.business.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tbit.common.entity.view.Result;
import com.tbit.manager.api.dto.OperationalDataDTO;
import com.tbit.uqbike.constant.AccountDayStatConstant;
import com.tbit.uqbike.constant.enums.AccountDayStatEnum;
import com.tbit.uqbike.object.pojo.AccountDayStat;
import com.tbit.uqbike.object.pojo.vo.*;
import com.tbit.uqbike.service.business.AccountDayStatService;
import com.tbit.uqbike.service.business.AccountService;
import com.tbit.uqbike.webmanager.dao.capital.BadOrderDao;
import com.tbit.uqbike.webmanager.dao.stat.AccountDayStatDao;
import com.tbit.uqbike.webmanager.dao.stat.OrderAnalysisDao;
import com.tbit.uqbike.webmanager.util.DateUtils;
import com.tbit.utils.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 区域数据预统计接口实现类
 *
 * @Author:BUGTian
 * @DATE: 2022/11/1
 */
@Service
public class AccountDayStatServiceImpl extends ServiceImpl<AccountDayStatDao, AccountDayStat> implements AccountDayStatService {

    /**
     * 金额类型的计算
     */
    private static final int SUM = 0;
    /**
     * 数量类型的计算
     */
    private static final int CNT = 1;
    /**
     * 净收入的计算
     */
    private static final int PURE = 2;

    @Autowired
    private AccountDayStatDao accountDayStatDao;
    @Autowired
    private BadOrderDao badOrderDao;
    @Autowired
    private OrderAnalysisDao orderAnalysisDao;
    @Autowired
    private AccountService accountService;

    /**
     * yyyyMMdd格式转yyyy-MM-dd格式
     *
     * @param time
     * @return
     */
    private static String reparseTime(Integer time) {
        if (time == null) {
            return null;
        }
        String s = time.toString();
        if (s.length() != 8) {
            return null;
        }
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < 8; i++) {
            stringBuilder.append(s.charAt(i));
            if (i == 3 || i == 5) {
                stringBuilder.append("-");
            }
        }
        return stringBuilder.toString();
    }

    @Override
    public Map<String, Object> operationalData(OperationalDataDTO operationalDataDTO) {
        Assert.notNulls("参数有误", operationalDataDTO.getAccountIds(), operationalDataDTO.getStartTime(), operationalDataDTO.getEndTime(), operationalDataDTO.getBrandId());
        Integer startTime = null;
        Integer endTime = null;
        if (operationalDataDTO.getStartTime() != null && operationalDataDTO.getEndTime() != null) {
            startTime = parseTime(operationalDataDTO.getStartTime());
            endTime = parseTime(operationalDataDTO.getEndTime());
        }
        List<Integer> accountIdList = operationalDataDTO.getAccountIdList();
        Date lastUpdateTime = accountDayStatDao.selectLatelyDataTime(operationalDataDTO.getAccountIdList());
        Map<Integer, Map<String, BigDecimal>> dataMap = accountDayStatDao.operationalData(startTime, endTime, accountIdList, null, operationalDataDTO.getBrandId());
        Map<String, Object> resultMap = initResultMap(dataMap, AccountDayStatEnum.values());
        resultMap.put("lastUpdateTime", lastUpdateTime);
        //计算净收入
        computePure(AccountDayStatEnum.REVENUE_FROM_MERCHANT_PLATFORM, AccountDayStatEnum.MERCHANT_PLATFORM_EXPENDITURE, resultMap, dataMap);
        computePure(AccountDayStatEnum.WECHAT_MERCHANT_INCOME, AccountDayStatEnum.WECHAT_MERCHANT_SPENDING, resultMap, dataMap);
        computePure(AccountDayStatEnum.ALIPAY_MERCHANT_INCOME, AccountDayStatEnum.ALIPAY_MERCHANT_EXPENSES, resultMap, dataMap);
        computePure(AccountDayStatEnum.INCOME_FROM_CYCLING_CARD, AccountDayStatEnum.BIKE_CARD_EXPENDITURE, resultMap, dataMap);
        computePure(AccountDayStatEnum.MEMBERSHIP_CARD_INCOME, AccountDayStatEnum.MEMBERSHIP_CARD_EXPENDITURE, resultMap, dataMap);
        computePure(AccountDayStatEnum.CARD_FREE_INCOME, AccountDayStatEnum.CHARGE_FREE_CARD_EXPENDITURE, resultMap, dataMap);
        computePure(AccountDayStatEnum.COUPON_PACKAGE_INCOME, AccountDayStatEnum.COUPON_PACKAGE_EXPENDITURE, resultMap, dataMap);
        computePure(AccountDayStatEnum.REMITTANCE_OF_MERCHANT_INCOME, AccountDayStatEnum.REMITTING_PAYMENTS_TO_MERCHANTS, resultMap, dataMap);
        computePure(AccountDayStatEnum.CYCLING_INCOME, AccountDayStatEnum.CYCLING_EXPENSES, resultMap, dataMap);
        computePure(AccountDayStatEnum.USER_FINE_INCOME, AccountDayStatEnum.USER_PENALTY_EXPENDITURE, resultMap, dataMap);
        computePure(AccountDayStatEnum.PURCHASE_INCOME, AccountDayStatEnum.PURCHASE_COSTS, resultMap, dataMap);
        computePure(AccountDayStatEnum.USER_RECHARGE_INCOME, AccountDayStatEnum.USER_RECHARGE_EXPENDITURE, resultMap, dataMap);
        computePure(AccountDayStatEnum.USER_DEPOSIT_INCOME, AccountDayStatEnum.USER_DEPOSIT_EXPENDITURE, resultMap, dataMap);
        computePure(AccountDayStatEnum.OPERATING_INCOME, AccountDayStatEnum.OPERATING_EXPENSES, resultMap, dataMap);
        computePure(AccountDayStatEnum.AMOUNT_OWED, AccountDayStatEnum.RECHARGE_AMOUNT_OF_ARREARS, resultMap, dataMap);

        computePure(AccountDayStatEnum.MANUALLY_MODIFY_THE_ORDER_DEDUCTION_EXPENSE, AccountDayStatEnum.MANUALLY_MODIFY_THE_ORDER_DEDUCTION_FEE_REFUND, resultMap, dataMap);
        computePure(AccountDayStatEnum.GIFT_CARD_DEDUCTION, AccountDayStatEnum.REFUND_OF_GIFT_CARD_DEDUCTION_FEE, resultMap, dataMap);
        computePure(AccountDayStatEnum.CREDIT_CARD_VOUCHER_DEDUCTION, AccountDayStatEnum.CREDIT_CARD_VOUCHER_DEDUCTION_REFUND, resultMap, dataMap);
        computePure(AccountDayStatEnum.OTHER_VIRTUAL_DEDUCTION_EXPENSES, AccountDayStatEnum.REFUND_OF_OTHER_VIRTUAL_DEDUCTION_FEES, resultMap, dataMap);


        //期初期末数据
        Map<Integer, Map<String, BigDecimal>> startDataMap = accountDayStatDao.operationalData(null, null, accountIdList, parseTime(DateUtil.offsetDay(operationalDataDTO.getStartTime(), -1)), operationalDataDTO.getBrandId());
        resultMap.put("startDataMap", initResultMap(startDataMap, AccountDayStatEnum.getAtTheBeginningTheFinalEnums()));
        Map<Integer, Map<String, BigDecimal>> endDataMap = accountDayStatDao.operationalData(null, null, accountIdList, endTime, operationalDataDTO.getBrandId());
        resultMap.put("endDataMap", initResultMap(endDataMap, AccountDayStatEnum.getAtTheBeginningTheFinalEnums()));
        //其他收入支出数据
        Date selectEndTime = DateUtils.getDayOnTheHour(operationalDataDTO.getEndTime());
        Map<String, Object> otherDataMap = badOrderDao.selectOtherDataMap(operationalDataDTO.getStartTime(), selectEndTime, accountIdList, operationalDataDTO.getBrandId());
        //其他净收入计算
        otherDataMap.put("orderMoneyPure", NumberUtil.sub(getValue(otherDataMap, "otherIncomeMoney"), getValue(otherDataMap, "otherExpensesMoney")));
        resultMap.put("otherDataMap", otherDataMap);
        String nowDay = LocalDate.now().toString();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String endDateStr = format.format(operationalDataDTO.getEndTime());
        // 如果是结束时间是当天，将期末其他收支金额设置为0
        if (Objects.equals(nowDay,endDateStr)){
            otherDataMap.put("endOtherMoney",0);
        }
        //用车虚拟金额计算
        computeVirtual(resultMap);
        //需要额外单独计算的字段
        computeExtra(resultMap);
        return resultMap;
    }

    /**
     * 运营数据 新
     * @param operationalDataDTO operationalDataDTO
     * @return OperationalDataVO
     */
    @Override
    public Result<OperationalDataVO> operationalDataNew(OperationalDataDTO operationalDataDTO) {
        Assert.notNulls("参数异常", operationalDataDTO.getAccountIds(),
                operationalDataDTO.getStartTime(), operationalDataDTO.getEndTime(), operationalDataDTO.getBrandId());
        List<Integer> accountIdList = operationalDataDTO.getAccountIdList();


        Map<String, Object> resultMap = getOperationalDataVOResult(operationalDataDTO,
                operationalDataDTO.getStartTime(), operationalDataDTO.getEndTime(), accountIdList);
        //封装数据
        if (CollectionUtil.isEmpty(resultMap)){
            return Result.error("暂无数据");
        }
        OperationalDataVO operationalDataVO = new OperationalDataVO();
        encapsulateData(operationalDataVO, resultMap);


        // 获取当前周期的时间范围
        LocalDate currentStartDate = operationalDataDTO.getStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate currentEndDate = operationalDataDTO.getEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

        // 获取上个周期的时间范围
        LocalDate lastStartDate = currentStartDate.minusDays(currentEndDate.toEpochDay() - currentStartDate.toEpochDay() + 1);
        LocalDate lastEndDate = currentEndDate.minusDays(currentEndDate.toEpochDay() - currentStartDate.toEpochDay() + 1);

        //环比
        Map<String, Object> monopolyResultMap = getOperationalDataVOResult(operationalDataDTO, Date.from(lastStartDate.atStartOfDay(ZoneId.systemDefault()).toInstant()),
                Date.from(lastEndDate.atStartOfDay(ZoneId.systemDefault()).toInstant()), accountIdList);
        if(CollectionUtil.isNotEmpty(monopolyResultMap)){
            monopoly(monopolyResultMap, operationalDataVO, 1);
        }

        //同比
        Date[] lastRange = getLastRange(operationalDataDTO.getStartTime(), operationalDataDTO.getEndTime(), 1, 2);
        Map<String, Object> operationalDataVOResult = getOperationalDataVOResult(operationalDataDTO, lastRange[0], lastRange[1], accountIdList);

        //运营净收入同比
        if (CollectionUtil.isNotEmpty(operationalDataVOResult)){
            monopoly(operationalDataVOResult, operationalDataVO, 2);
        }
        return Result.success(operationalDataVO);
    }

    /**
     * 获取预统计数据
     * @param operationalDataDTO operationalDataDTO
     * @param startDate          开始时间
     * @param endDate            结束时间
     * @param accountIdList      区域id
     * @return Map<String, Object>
     */
    private Map<String, Object> getOperationalDataVOResult(OperationalDataDTO operationalDataDTO, Date startDate, Date endDate, List<Integer> accountIdList) {
        Map<Integer, Map<String, BigDecimal>> dataMap = accountDayStatDao.operationalDataNew(parseTime(startDate),
                parseTime(endDate), accountIdList, operationalDataDTO.getBrandId(), AccountDayStatEnum.getOperationalDataType());
        if (CollectionUtils.isEmpty(dataMap)){
            return null;
        }
        Map<String, Object> map = initResultMap(dataMap, AccountDayStatEnum.getOperationEnums());
        //净收入
        computePure(AccountDayStatEnum.CYCLING_INCOME, AccountDayStatEnum.CYCLING_EXPENSES, map, dataMap);
        computePure(AccountDayStatEnum.USER_FINE_INCOME, AccountDayStatEnum.USER_PENALTY_EXPENDITURE, map, dataMap);
        computePure(AccountDayStatEnum.PURCHASE_INCOME, AccountDayStatEnum.PURCHASE_COSTS, map, dataMap);
        computePure(AccountDayStatEnum.OPERATING_INCOME, AccountDayStatEnum.OPERATING_EXPENSES, map, dataMap);
        return map;
    }


    /**
     * 运营数据 环比-同比
     * @param monopolyResultMap monopolyResultMap
     * @param operationalDataVO operationalDataVO
     * @param type 1-环比 2-同比
     */
    private void monopoly(Map<String, Object> monopolyResultMap, OperationalDataVO operationalDataVO, Integer type) {
        //运营净收入环比
        if (Objects.nonNull(monopolyResultMap.get(AccountDayStatEnum.OPERATING_INCOME.getPureFileIdName()))){
            if (0 != Double.parseDouble(monopolyResultMap.get(AccountDayStatEnum.OPERATING_INCOME.getPureFileIdName()).toString())){
                double sub = NumberUtil.sub(operationalDataVO.getNetOperatingIncome().doubleValue(),
                        Double.parseDouble(monopolyResultMap.get(AccountDayStatEnum.OPERATING_INCOME.getPureFileIdName()).toString()));
                double div = NumberUtil.mul(NumberUtil.div(sub, Double.parseDouble(monopolyResultMap.get(AccountDayStatEnum.OPERATING_INCOME.getPureFileIdName()).toString()), 4), 100);
                if (1 == type){
                    operationalDataVO.setNetOperatingIncomeMonthOnMonth(div);
                }else if (2 == type){
                    operationalDataVO.setNetOperatingIncomeYearOnYear(div);
                }
            }
        }
        //骑行费用净收入环比
        if (Objects.nonNull(monopolyResultMap.get(AccountDayStatEnum.CYCLING_INCOME.getPureFileIdName()))){
            if (0 != Double.parseDouble(monopolyResultMap.get(AccountDayStatEnum.CYCLING_INCOME.getPureFileIdName()).toString())){
                double sub = NumberUtil.sub(operationalDataVO.getNetIncomeFromRidingExpenses().doubleValue(),
                        Double.parseDouble(monopolyResultMap.get(AccountDayStatEnum.CYCLING_INCOME.getPureFileIdName()).toString()));
                double div = NumberUtil.mul(NumberUtil.div(sub, Double.parseDouble(monopolyResultMap.get(AccountDayStatEnum.CYCLING_INCOME.getPureFileIdName()).toString()), 4), 100);
                if (1 == type){
                    operationalDataVO.setNetIncomeFromRidingExpensesMonthOnMonth(div);
                }else if (2 == type){
                    operationalDataVO.setNetIncomeFromRidingExpensesYearOnYear(div);
                }
            }
         }
        //用户罚款净收入环比
        if (Objects.nonNull(monopolyResultMap.get(AccountDayStatEnum.USER_FINE_INCOME.getPureFileIdName()))){
            if (0 != Double.parseDouble(monopolyResultMap.get(AccountDayStatEnum.USER_FINE_INCOME.getPureFileIdName()).toString())){
                double sub = NumberUtil.sub(operationalDataVO.getUserFinesNetIncome().doubleValue(),
                        Double.parseDouble(monopolyResultMap.get(AccountDayStatEnum.USER_FINE_INCOME.getPureFileIdName()).toString()));
                double div = NumberUtil.mul(NumberUtil.div(sub, Double.parseDouble(monopolyResultMap.get(AccountDayStatEnum.USER_FINE_INCOME.getPureFileIdName()).toString()), 4), 100);
                if (1 == type){
                    operationalDataVO.setUserFinesNetIncomeMonthOnMonth(div);
                }else if (2 == type){
                    operationalDataVO.setUserFinesNetIncomeYearOnYear(div);
                }
            }
        }
        //用户购卡净收入环比
        if (Objects.nonNull(monopolyResultMap.get(AccountDayStatEnum.PURCHASE_INCOME.getPureFileIdName()))){
            if (0 != Double.parseDouble(monopolyResultMap.get(AccountDayStatEnum.PURCHASE_INCOME.getPureFileIdName()).toString())){
                double sub = NumberUtil.sub(operationalDataVO.getNetIncomeFromUsersCardPurchases().doubleValue(),
                        Double.parseDouble(monopolyResultMap.get(AccountDayStatEnum.PURCHASE_INCOME.getPureFileIdName()).toString()));
                double div = NumberUtil.mul(NumberUtil.div(sub, Double.parseDouble(monopolyResultMap.get(AccountDayStatEnum.PURCHASE_INCOME.getPureFileIdName()).toString()), 4), 100);
                if (1 == type){
                    operationalDataVO.setNetIncomeFromUsersCardPurchasesMonthOnMonth(div);
                }else if (2 == type){
                    operationalDataVO.setNetIncomeFromUsersCardPurchasesYearOnYear(div);
                }
            }
        }
    }


    /**
     * 封装数据
     * @param operationalDataVO operationalDataVO
     * @param resultMap 预统计结果
     */
    private void encapsulateData(OperationalDataVO operationalDataVO, Map<String, Object> resultMap) {
        operationalDataVO
                .setNetOperatingIncome(Double.parseDouble(resultMap.getOrDefault(AccountDayStatEnum.OPERATING_INCOME.getPureFileIdName(), 0).toString()))
                .setNetIncomeFromRidingExpenses(Double.parseDouble(resultMap.getOrDefault(AccountDayStatEnum.CYCLING_INCOME.getPureFileIdName(), 0).toString()))
                .setUserFinesNetIncome(Double.parseDouble(resultMap.getOrDefault(AccountDayStatEnum.USER_FINE_INCOME.getPureFileIdName(), 0).toString()))
                .setNetIncomeFromUsersCardPurchases(Double.parseDouble(resultMap.getOrDefault(AccountDayStatEnum.PURCHASE_INCOME.getPureFileIdName(), 0).toString()))
                .setTotalOperatingRevenue(Double.parseDouble(resultMap.getOrDefault(AccountDayStatEnum.OPERATING_INCOME.getSumFieldName(), 0).toString()))
                .setNumberOfOperatingOrders(Integer.parseInt(resultMap.getOrDefault(AccountDayStatEnum.OPERATING_INCOME.getCntFieldName(), 0).toString()))
                .setTotalRevenueForRidingExpenses(Double.parseDouble(resultMap.getOrDefault(AccountDayStatEnum.CYCLING_INCOME.getSumFieldName(), 0).toString()))
                .setNumberOfRidingExpensesOrders(Integer.parseInt(resultMap.getOrDefault(AccountDayStatEnum.CYCLING_INCOME.getCntFieldName(), 0).toString()))
                .setTotalUserFines(Double.parseDouble(resultMap.getOrDefault(AccountDayStatEnum.USER_FINE_INCOME.getSumFieldName(), 0).toString()))
                .setNumberOfUserFinesOrders(Integer.parseInt(resultMap.getOrDefault(AccountDayStatEnum.USER_FINE_INCOME.getCntFieldName(), 0).toString()))
                .setTotalCardPurchaseIncomeForUsers(Double.parseDouble(resultMap.getOrDefault(AccountDayStatEnum.PURCHASE_INCOME.getSumFieldName(), 0).toString()))
                .setNumberOfCardPurchaseOrders(Integer.parseInt(resultMap.getOrDefault(AccountDayStatEnum.PURCHASE_INCOME.getCntFieldName(), 0).toString()))
                .setTotalOperationRefund(Double.parseDouble(resultMap.getOrDefault(AccountDayStatEnum.OPERATING_EXPENSES.getSumFieldName(), 0).toString()))
                .setNumberOfRefundOrders(Integer.parseInt(resultMap.getOrDefault(AccountDayStatEnum.OPERATING_EXPENSES.getCntFieldName(), 0).toString()))
                .setTotalRefundForRidingFees(Double.parseDouble(resultMap.getOrDefault(AccountDayStatEnum.CYCLING_EXPENSES.getSumFieldName(), 0).toString()))
                .setNumberOfRidingFeesRefundOrders(Integer.parseInt(resultMap.getOrDefault(AccountDayStatEnum.CYCLING_EXPENSES.getCntFieldName(), 0).toString()))
                .setUserFineRefund(Double.parseDouble(resultMap.getOrDefault(AccountDayStatEnum.USER_PENALTY_EXPENDITURE.getSumFieldName(), 0).toString()))
                .setNumberOfUserFineRefundOrders(Integer.parseInt(resultMap.getOrDefault(AccountDayStatEnum.USER_PENALTY_EXPENDITURE.getCntFieldName(), 0).toString()))
                .setTotalRefundForUserCardPurchase(Double.parseDouble(resultMap.getOrDefault(AccountDayStatEnum.PURCHASE_COSTS.getSumFieldName(), 0).toString()))
                .setNumberOfUserCardPurchaseRefundOrders(Integer.parseInt(resultMap.getOrDefault(AccountDayStatEnum.PURCHASE_COSTS.getCntFieldName(), 0).toString()));
    }

    /**
     * 需要额外计算的字段，主要解决前端自己计算精度丢失问题
     *
     * @param resultMap
     */
    private void computeExtra(Map<String, Object> resultMap) {
        Map<String, Object> map = new HashMap<>();
        //预存款正常支出和支出笔数(用户退款+骑行消费)
        double normalExpenditureSum = NumberUtil.add(
                getValue(resultMap, AccountDayStatEnum.USER_RECHARGE_EXPENDITURE.getSumFieldName()),
                getValue(resultMap, AccountDayStatEnum.CYCLING_CONSUMPTION_EXPENDITURE.getSumFieldName())
        );
        map.put("normal_expenditure_of_advance_deposit_sum", normalExpenditureSum);
        map.put("normal_expenditure_of_advance_deposit_cnt", (int) NumberUtil.add(
                getValue(resultMap, AccountDayStatEnum.USER_RECHARGE_EXPENDITURE.getCntFieldName()),
                getValue(resultMap, AccountDayStatEnum.CYCLING_CONSUMPTION_EXPENDITURE.getCntFieldName())
        ));
        map.put("normal_income_of_advance_deposit_pure", NumberUtil.sub(
                getValue(resultMap, AccountDayStatEnum.USER_RECHARGE_INCOME.getSumFieldName()),
                new Double(normalExpenditureSum)
        ));
        //本期预存款收入和支出
        map.put("current_deposit_income_sum", NumberUtil.add(
                getValue(resultMap, AccountDayStatEnum.USER_RECHARGE_INCOME.getSumFieldName()),
                getValue(resultMap, AccountDayStatEnum.MANUAL_RECHARGE.getSumFieldName())
        ));
        map.put("current_deposit_income_cnt", (int) NumberUtil.add(
                getValue(resultMap, AccountDayStatEnum.USER_RECHARGE_INCOME.getCntFieldName()),
                getValue(resultMap, AccountDayStatEnum.MANUAL_RECHARGE.getCntFieldName())
        ));
        map.put("current_deposit_expenditure_sum", NumberUtil.add(
                getValue(resultMap, AccountDayStatEnum.USER_RECHARGE_EXPENDITURE.getSumFieldName()),
                getValue(resultMap, AccountDayStatEnum.CYCLING_CONSUMPTION_EXPENDITURE.getSumFieldName()),
                getValue(resultMap, AccountDayStatEnum.MANUAL_DEDUCTION.getSumFieldName())
        ));
        map.put("current_deposit_expenditure_cnt", NumberUtil.add(
                getValue(resultMap, AccountDayStatEnum.USER_RECHARGE_EXPENDITURE.getCntFieldName()),
                getValue(resultMap, AccountDayStatEnum.CYCLING_CONSUMPTION_EXPENDITURE.getCntFieldName()),
                getValue(resultMap, AccountDayStatEnum.MANUAL_DEDUCTION.getCntFieldName())
        ).intValue());
        //礼品卡
        BigDecimal giftCardIncomeSum = NumberUtil.add(
                getValue(resultMap, AccountDayStatEnum.GIFT_CARD_REDEMPTION.getSumFieldName()),
                getValue(resultMap, AccountDayStatEnum.MANUAL_RECHARGE_GIFT_CARD.getSumFieldName()),
                getValue(resultMap, AccountDayStatEnum.USER_RECHARGE_GIFT_CARD.getSumFieldName())
        );
        map.put("current_gift_card_income_sum", giftCardIncomeSum);
        map.put("current_gift_card_income_cnt", NumberUtil.add(
                getValue(resultMap, AccountDayStatEnum.GIFT_CARD_REDEMPTION.getCntFieldName()),
                getValue(resultMap, AccountDayStatEnum.MANUAL_RECHARGE_GIFT_CARD.getCntFieldName()),
                getValue(resultMap, AccountDayStatEnum.USER_RECHARGE_GIFT_CARD.getCntFieldName())
        ).intValue());
        BigDecimal giftCardExpenditureSum = NumberUtil.add(
                getValue(resultMap, AccountDayStatEnum.RIDING_DISCOUNT_GIFT_CARD.getSumFieldName()),
                getValue(resultMap, AccountDayStatEnum.MANUALLY_DEDUCT_GIFT_CARDS.getSumFieldName()),
                getValue(resultMap, AccountDayStatEnum.USER_REFUNDS_DEDUCT_GIFT_CARDS.getSumFieldName())
        );
        map.put("current_gift_card_expenditure_sum", giftCardExpenditureSum);
        map.put("current_gift_card_expenditure_cnt", NumberUtil.add(
                getValue(resultMap, AccountDayStatEnum.RIDING_DISCOUNT_GIFT_CARD.getCntFieldName()),
                getValue(resultMap, AccountDayStatEnum.MANUALLY_DEDUCT_GIFT_CARDS.getCntFieldName()),
                getValue(resultMap, AccountDayStatEnum.USER_REFUNDS_DEDUCT_GIFT_CARDS.getCntFieldName())
        ).intValue());
        map.put("current_gift_card_income_pure", NumberUtil.sub(giftCardIncomeSum, giftCardExpenditureSum));
        //欠款补交
        map.put("payment_of_arrears_pure", NumberUtil.sub(
                getValue(resultMap, AccountDayStatEnum.AMOUNT_OWED.getSumFieldName()),
                getValue(resultMap, AccountDayStatEnum.RECHARGE_AMOUNT_OF_ARREARS.getSumFieldName()),
                getValue(resultMap, AccountDayStatEnum.SUPPLEMENTARY_VIRTUAL_AMOUNT_OF_ARREARS.getSumFieldName())
        ));
        map.put("current_payment_of_arrears_sum", NumberUtil.add(
                getValue(resultMap, AccountDayStatEnum.RECHARGE_AMOUNT_OF_ARREARS.getSumFieldName()),
                getValue(resultMap, AccountDayStatEnum.SUPPLEMENTARY_VIRTUAL_AMOUNT_OF_ARREARS.getSumFieldName())
        ));
        map.put("current_payment_of_arrears_cnt", NumberUtil.add(
                getValue(resultMap, AccountDayStatEnum.RECHARGE_AMOUNT_OF_ARREARS.getCntFieldName()),
                getValue(resultMap, AccountDayStatEnum.SUPPLEMENTARY_VIRTUAL_AMOUNT_OF_ARREARS.getCntFieldName())
        ));
        resultMap.put("extraDataMap", map);
    }

    private Double getValue(Map<String, Object> resultMap, String key) {
        Double value = 0D;
        Object o = resultMap.get(key);
        if (o == null) {
            return value;
        }
        return new Double(o.toString());
    }

    @Override
    public VehicleOperationVO queryVehicleOperationVO(OperationalDataDTO operationalDataDTO) {
        List<Integer> accountIdList = operationalDataDTO.getAccountIdList();
        //获取区间间隔的每一天
        Date startTime = operationalDataDTO.getStartTime();
        Date endTime = operationalDataDTO.getEndTime();
        List<String> betweenEveryDay = AdopterMsgServiceImpl.getBetweenEveryDay(startTime, endTime);
        Date lastUpdateTime = accountDayStatDao.selectLatelyDataTime(accountIdList);
        List<AccountDayStat> accountDayStatList = accountDayStatDao.sumAccountAndType(operationalDataDTO.getBrandId(), accountIdList, parseTime(startTime), parseTime(endTime), AccountDayStatEnum.getVehicleType());
        Map<String, AccountDayStat> map = new HashMap<>();
        VehicleOperationSumVO vehicleOperationSumVO = new VehicleOperationSumVO();
        for (AccountDayStat accountDayStat : accountDayStatList) {
            map.put(reparseTime(accountDayStat.getDataDate()) + "_" + accountDayStat.getDataType(), accountDayStat);
            //最后一天的汇总
            if (accountDayStat.getDataDate().equals(parseTime(endTime))) {
                switch (accountDayStat.getDataType()) {
                    case AccountDayStatConstant.TOTAL_NUMBER_OF_VEHICLES:
                        //车辆总数
                        vehicleOperationSumVO.setTotalVehicle(vehicleOperationSumVO.getTotalVehicle() + accountDayStat.getCntTotal());
                        break;
                    case AccountDayStatConstant.NUMBER_OF_VEHICLES_LAUNCHED:
                        //已投放车辆数
                        vehicleOperationSumVO.setPutInTotalVehicle(vehicleOperationSumVO.getPutInTotalVehicle() + accountDayStat.getCntTotal());
                        break;
                    case AccountDayStatConstant.NUMBER_OF_OPERATIONAL_VEHICLES:
                        vehicleOperationSumVO.setOperationalVehicles(vehicleOperationSumVO.getOperationalVehicles() + accountDayStat.getCntTotal());
                        //可运营车辆数
                        break;
                    default:
                        break;
                }
            }
        }
        //计算不可运营车辆总数和未投放车辆总数
        vehicleOperationSumVO.compute();
        long totalIncomeMoney = accountDayStatList.stream()
                .filter(accountDayStat -> Objects.equals(accountDayStat.getDataType(), AccountDayStatConstant.CYCLING_INCOME)
                        || Objects.equals(accountDayStat.getDataType(), AccountDayStatConstant.USER_FINE_INCOME))
                .mapToLong(AccountDayStat::getSumTotal)
                .sum();
        long orderCount = accountDayStatList.stream()
                .filter(accountDayStat -> Objects.equals(accountDayStat.getDataType(), AccountDayStatConstant.CYCLING_INCOME))
                .mapToLong(AccountDayStat::getCntTotal)
                .sum();
        //车均收入
        if (vehicleOperationSumVO.getTotalVehicle() <= 0) {
            vehicleOperationSumVO.setCarsWereIncome(0);
            vehicleOperationSumVO.setNumberOfCarsOnOrder(0);
        } else {
            vehicleOperationSumVO.setCarsWereIncome(NumberUtil.div(NumberUtil.div(totalIncomeMoney, 100, 2), vehicleOperationSumVO.getTotalVehicle(), 2));
            vehicleOperationSumVO.setNumberOfCarsOnOrder(NumberUtil.div(orderCount, vehicleOperationSumVO.getTotalVehicle(), 2));
        }
        //车辆总数折线图数据
        List<Object> totalNumberOfVehicles = new LinkedList<>();
        //投放车辆总数折线图数据
        List<Object> totalNumberOfVehiclesLaunched = new LinkedList<>();
        //可运营车辆总数折线图数据
        List<Object> totalNumberOfOperationalVehicles = new LinkedList<>();
        //车均收入折线图数据
        List<Object> carsWereIncome = new LinkedList<>();
        //车均订单折线图数据
        List<Object> carAllOrders = new LinkedList<>();
        for (String day : betweenEveryDay) {
            chartDataAdd(totalNumberOfVehicles, day, AccountDayStatEnum.TOTAL_NUMBER_OF_VEHICLES, map, CNT, null);
            chartDataAdd(totalNumberOfVehiclesLaunched, day, AccountDayStatEnum.NUMBER_OF_VEHICLES_LAUNCHED, map, CNT, null);
            chartDataAdd(totalNumberOfOperationalVehicles, day, AccountDayStatEnum.NUMBER_OF_OPERATIONAL_VEHICLES, map, CNT, null);
            //车均收入和车均订单要单独计算
            long vehicleCount = getValue(map, AccountDayStatEnum.TOTAL_NUMBER_OF_VEHICLES, day, CNT);
            long rideMoney = getValue(map, AccountDayStatEnum.CYCLING_INCOME, day, SUM) + getValue(map, AccountDayStatEnum.USER_FINE_INCOME, day, SUM);
            long rideCount = getValue(map, AccountDayStatEnum.CYCLING_INCOME, day, CNT);
            carsWereIncome.add(vehicleCount == 0 ? 0D : NumberUtil.div(NumberUtil.div(rideMoney, 100, 2), vehicleCount, 2));
            carAllOrders.add(vehicleCount == 0 ? 0 : rideCount == 0 ? 0 : NumberUtil.div(rideCount, vehicleCount, 2));
            //chartDataAdd(carsWereIncome, day, AccountDayStatEnum.AVERAGE_VEHICLE_INCOME, map, SUM, null);
            //chartDataAdd(carAllOrders, day, AccountDayStatEnum.NUMBER_OF_ORDERS_PER_VEHICLE, map, CNT, null);
        }
        List<String> betweenDay = betweenEveryDay.stream().map(s -> s.substring(s.indexOf("-") + 1)).collect(Collectors.toList());
        return new VehicleOperationVO(lastUpdateTime,
                vehicleOperationSumVO,
                new VehicleOperationLineChartVO()
                        .setDateList(betweenDay)
                        .setCarAllOrders(carAllOrders)
                        .setCarsWereIncome(carsWereIncome)
                        .setTotalNumberOfOperationalVehicles(totalNumberOfOperationalVehicles)
                        .setTotalNumberOfVehicles(totalNumberOfVehicles)
                        .setTotalNumberOfVehiclesLaunched(totalNumberOfVehiclesLaunched));
    }

    @Override
    public OrderFlowKanbanVO orderFlowKanban(OperationalDataDTO operationalDataDTO) {
        List<Integer> accountIdList = operationalDataDTO.getAccountIdList();
        List<String> betweenEveryDay = AdopterMsgServiceImpl.getBetweenEveryDay(operationalDataDTO.getStartTime(), operationalDataDTO.getEndTime());
        Date lastUpdateTime = accountDayStatDao.selectLatelyDataTime(accountIdList);
        List<AccountDayStat> accountDayStatList = accountDayStatDao.sumAccountAndType(operationalDataDTO.getBrandId(), accountIdList, parseTime(operationalDataDTO.getStartTime()), parseTime(operationalDataDTO.getEndTime()), AccountDayStatEnum.getOrderType());
        Map<String, AccountDayStat> map = new HashMap<>();
        for (AccountDayStat accountDayStat : accountDayStatList) {
            map.put(reparseTime(accountDayStat.getDataDate()) + "_" + accountDayStat.getDataType(), accountDayStat);
        }
        //运营营收净收入
        List<Object> operatingIncomePureList = new LinkedList<>();
        //运营营收订单数
        List<Object> operatingIncomeCntList = new LinkedList<>();
        //骑行净收入
        List<Object> cyclingIncomePureList = new LinkedList<>();
        //骑行订单数
        List<Object> cyclingIncomeCntList = new LinkedList<>();
        //用户罚款净收入
        List<Object> userFineIncomePureList = new LinkedList<>();
        //用户罚款订单数
        List<Object> userFineIncomeCntList = new LinkedList<>();
        //用户购卡净收入
        List<Object> purchaseIncomePureList = new LinkedList<>();
        //用户购卡订单数
        List<Object> purchaseIncomeCntList = new LinkedList<>();
        //骑行卡净收入
        List<Object> incomeFromCyclingCardPureList = new LinkedList<>();
        //骑行卡订单数
        List<Object> incomeFromCyclingCardCntList = new LinkedList<>();
        //会员卡净收入
        List<Object> membershipCardIncomePureList = new LinkedList<>();
        //会员卡订单数
        List<Object> membershipCardIncomeCntList = new LinkedList<>();
        //免押卡净收入
        List<Object> cardFreeIncomePureList = new LinkedList<>();
        //免押卡订单数
        List<Object> cardFreeIncomeCntList = new LinkedList<>();
        //优惠券套餐净收入
        List<Object> couponPackageIncomePureList = new LinkedList<>();
        //优惠券套餐订单数
        List<Object> couponPackageIncomeCntList = new LinkedList<>();
        for (String day : betweenEveryDay) {
            chartDataAdd(operatingIncomePureList, day, AccountDayStatEnum.OPERATING_INCOME, map, PURE, AccountDayStatEnum.OPERATING_EXPENSES);
            chartDataAdd(operatingIncomeCntList, day, AccountDayStatEnum.OPERATING_INCOME, map, CNT, null);
            chartDataAdd(cyclingIncomePureList, day, AccountDayStatEnum.CYCLING_INCOME, map, PURE, AccountDayStatEnum.CYCLING_EXPENSES);
            chartDataAdd(cyclingIncomeCntList, day, AccountDayStatEnum.CYCLING_INCOME, map, CNT, null);
            chartDataAdd(userFineIncomePureList, day, AccountDayStatEnum.USER_FINE_INCOME, map, PURE, AccountDayStatEnum.USER_PENALTY_EXPENDITURE);
            chartDataAdd(userFineIncomeCntList, day, AccountDayStatEnum.USER_FINE_INCOME, map, CNT, null);
            chartDataAdd(purchaseIncomePureList, day, AccountDayStatEnum.PURCHASE_INCOME, map, PURE, AccountDayStatEnum.PURCHASE_COSTS);
            chartDataAdd(purchaseIncomeCntList, day, AccountDayStatEnum.PURCHASE_INCOME, map, CNT, null);
            chartDataAdd(incomeFromCyclingCardPureList, day, AccountDayStatEnum.INCOME_FROM_CYCLING_CARD, map, PURE, AccountDayStatEnum.BIKE_CARD_EXPENDITURE);
            chartDataAdd(incomeFromCyclingCardCntList, day, AccountDayStatEnum.INCOME_FROM_CYCLING_CARD, map, CNT, null);
            chartDataAdd(membershipCardIncomePureList, day, AccountDayStatEnum.MEMBERSHIP_CARD_INCOME, map, PURE, AccountDayStatEnum.MEMBERSHIP_CARD_EXPENDITURE);
            chartDataAdd(membershipCardIncomeCntList, day, AccountDayStatEnum.MEMBERSHIP_CARD_INCOME, map, CNT, null);
            chartDataAdd(cardFreeIncomePureList, day, AccountDayStatEnum.CARD_FREE_INCOME, map, PURE, AccountDayStatEnum.CHARGE_FREE_CARD_EXPENDITURE);
            chartDataAdd(cardFreeIncomeCntList, day, AccountDayStatEnum.CARD_FREE_INCOME, map, CNT, null);
            chartDataAdd(couponPackageIncomePureList, day, AccountDayStatEnum.COUPON_PACKAGE_INCOME, map, PURE, AccountDayStatEnum.COUPON_PACKAGE_EXPENDITURE);
            chartDataAdd(couponPackageIncomeCntList, day, AccountDayStatEnum.COUPON_PACKAGE_INCOME, map, CNT, null);
        }
        List<String> betweenDay = betweenEveryDay.stream().map(s -> s.substring(s.indexOf("-") + 1)).collect(Collectors.toList());
        return new OrderFlowKanbanVO()
                .setLastUpdateTime(lastUpdateTime)
                .setDateList(betweenDay)
                .setOperatingIncomePureList(operatingIncomePureList)
                .setOperatingIncomeCntList(operatingIncomeCntList)
                .setCyclingIncomePureList(cyclingIncomePureList)
                .setCyclingIncomeCntList(cyclingIncomeCntList)
                .setUserFineIncomePureList(userFineIncomePureList)
                .setUserFineIncomeCntList(userFineIncomeCntList)
                .setPurchaseIncomePureList(purchaseIncomePureList)
                .setPurchaseIncomeCntList(purchaseIncomeCntList)
                .setIncomeFromCyclingCardPureList(incomeFromCyclingCardPureList)
                .setIncomeFromCyclingCardCntList(incomeFromCyclingCardCntList)
                .setMembershipCardIncomePureList(membershipCardIncomePureList)
                .setMembershipCardIncomeCntList(membershipCardIncomeCntList)
                .setCardFreeIncomePureList(cardFreeIncomePureList)
                .setCardFreeIncomeCntList(cardFreeIncomeCntList)
                .setCouponPackageIncomePureList(couponPackageIncomePureList)
                .setCouponPackageIncomeCntList(couponPackageIncomeCntList);
    }

    /**
     * 获取值
     *
     * @param map                存数据的map
     * @param accountDayStatEnum 枚举类
     * @param day                时间yyyy-MM-dd
     * @param type               类型 0：金额，1数量
     * @return
     */
    public long getValue(Map<String, AccountDayStat> map, AccountDayStatEnum accountDayStatEnum, String day, int type) {
        AccountDayStat accountDayStat = map.get(day + "_" + accountDayStatEnum.getDataType());
        long value = 0;
        if (accountDayStat == null) {
            return value;
        }
        switch (type) {
            case SUM:
                value = accountDayStat.getSumTotal();
                break;
            case CNT:
                value = accountDayStat.getCntTotal();
                break;
            default:
                break;
        }
        return value;
    }

    /**
     * 折线图数据构成
     *
     * @param chartList          折线图数据，按天对应
     * @param day                yyyy-MM-dd格式的日期字符串
     * @param accountDayStatEnum 数据对应的枚举类型
     * @param type               0:sum   1:cnt   2：pure
     * @param expenseEnum        支出枚举（计算净收入需要传这个）
     */
    public void chartDataAdd(List<Object> chartList, String day, AccountDayStatEnum accountDayStatEnum, Map<String, AccountDayStat> map, int type, AccountDayStatEnum expenseEnum) {
        AccountDayStat accountDayStat = map.get(day + "_" + accountDayStatEnum.getDataType());
        switch (type) {
            case SUM:
                //金额
                chartList.add(accountDayStat == null ? 0 : fenToYuan(accountDayStat.getSumTotal()));
                break;
            case CNT:
                //数量
                chartList.add(accountDayStat == null ? 0 : accountDayStat.getCntTotal());
                break;
            case PURE:
                if (expenseEnum == null) {
                    return;
                }
                //净收入
                AccountDayStat expense = map.get(day + "_" + expenseEnum.getDataType());
                long incomeMoney = accountDayStat == null ? 0L : accountDayStat.getSumTotal();
                long expenseMoney = expense == null ? 0L : expense.getSumTotal();
                chartList.add(fenToYuan(incomeMoney - expenseMoney));
                break;
            default:
                break;
        }
    }

    /**
     * 获取yyyyMMdd格式的时间
     *
     * @param date
     * @return
     */
    private Integer parseTime(Date date) {
        if (date == null) {
            return null;
        }
        return Integer.parseInt(DateUtil.format(date, "yyyyMMdd"));
    }

    private Map<String, Object> initResultMap(Map<Integer, Map<String, BigDecimal>> dataMap, List<Integer> excludeFenToYuan, AccountDayStatEnum... values) {
        Map<String, Object> resultMap = new HashMap<>();
        for (AccountDayStatEnum value : values) {
            Map<String, BigDecimal> stat = dataMap.get(value.getDataType());
            BigDecimal cntTotal = new BigDecimal(0);
            BigDecimal sumTotal = new BigDecimal(0);
            if (stat != null) {
                cntTotal = stat.get("cntTotal");
                sumTotal = stat.get("sumTotal");
            }
            resultMap.put(value.getCntFieldName(), cntTotal);
            if (excludeFenToYuan !=null && excludeFenToYuan.contains(value.getDataType())){
                resultMap.put(value.getSumFieldName(), sumTotal);
            }else {
                resultMap.put(value.getSumFieldName(), fenToYuan(sumTotal.longValue()));
            }
        }
        return resultMap;
    }

    /**
     * 初始化返回的map
     *
     * @param dataMap
     * @param values
     * @return
     */
    private Map<String, Object> initResultMap(Map<Integer, Map<String, BigDecimal>> dataMap, AccountDayStatEnum... values) {
        Map<String, Object> resultMap = new HashMap<>();
        for (AccountDayStatEnum value : values) {
            Map<String, BigDecimal> stat = dataMap.get(value.getDataType());
            BigDecimal cntTotal = new BigDecimal(0);
            BigDecimal sumTotal = new BigDecimal(0);
            if (stat != null) {
                cntTotal = stat.get("cntTotal");
                sumTotal = stat.get("sumTotal");
            }
            resultMap.put(value.getCntFieldName(), cntTotal);
            resultMap.put(value.getSumFieldName(), fenToYuan(sumTotal.longValue()));
        }
        return resultMap;
    }

    /**
     * 分转元
     *
     * @param fen
     * @return
     */
    public Double fenToYuan(long fen) {
        return fen == 0 ? 0.0D : (double) fen / 100;
    }


    /**
     * 计算净收入
     *
     * @param incomeEnum  收入枚举
     * @param expenseEnum 支出枚举
     * @param resultMap   返回的map
     * @param dataMap     数据库查询统计的数据
     */
    public void computePure(AccountDayStatEnum incomeEnum, AccountDayStatEnum expenseEnum, Map<String, Object> resultMap, Map<Integer, Map<String, BigDecimal>> dataMap) {
        //收入
        Map<String, BigDecimal> incomeStat = dataMap.get(incomeEnum.getDataType());
        long income = incomeStat == null ? 0 : incomeStat.get("sumTotal").longValue();
        //支出
        Map<String, BigDecimal> expenseStat = dataMap.get(expenseEnum.getDataType());
        long expense = expenseStat == null ? 0 : expenseStat.get("sumTotal").longValue();
        //净收入 = 收入-支出
        resultMap.put(incomeEnum.getPureFileIdName(), fenToYuan(income - expense));
    }

    @Override
    public Long selectLatelyDataTime(List<Integer> accountIds) {
        Date lastTime = getBaseMapper().selectLatelyDataTime(accountIds);
        if (lastTime == null) {
            return null;
        }
        return lastTime.getTime();
    }

    @Override
    public Integer todayNewUser(List<Integer> idList) {
        if (CollectionUtils.isEmpty(idList)){
            return 0;
        }
        Integer brandId = accountService.getBrandIdByAccountId(idList.get(0));
        return accountDayStatDao.getUserCount(brandId, idList,
                AccountDayStatEnum.NUMBER_OF_NEW_USERS.getDataType());
    }

    /**
     * 计算用车虚拟金额
     *
     * @param resultMap
     * @return
     */
    private void computeVirtual(Map<String, Object> resultMap) {
        Map<String, Object> virtualDataMap = new HashMap<>();
        AccountDayStatDownloadAllXuNiVO vo = JSON.parseObject(JSON.toJSONString(resultMap), AccountDayStatDownloadAllXuNiVO.class);
        virtualDataMap.put("virtual_amount_of_car_use_pure", vo.getTotal_sum().subtract(vo.getTotal_refund_sum()));
        virtualDataMap.put("virtual_amount_of_car_use_sum", vo.getTotal_sum());
        virtualDataMap.put("virtual_amount_of_car_use_cnt", vo.getTotal_cnt());
        virtualDataMap.put("virtual_amount_of_car_use_refund_sum", vo.getTotal_refund_sum());
        virtualDataMap.put("virtual_amount_of_car_use_refund_cnt", vo.getTotal_refund_cnt());
        virtualDataMap.put("credit_card_voucher_deduction_pure", vo.getCard_sum().subtract(vo.getCard_refund_sum()));
        virtualDataMap.put("credit_card_voucher_deduction_sum", vo.getCard_sum());
        virtualDataMap.put("credit_card_voucher_deduction_cnt", vo.getCard_cnt());
        virtualDataMap.put("credit_card_voucher_deduction_refund_sum", vo.getCard_refund_sum());
        virtualDataMap.put("credit_card_voucher_deduction_refund_cnt", vo.getCard_refund_cnt());
        resultMap.put("virtualDataMap", virtualDataMap);
    }


    /**
     * 根据类型获取对应时间范围
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @param count     数量
     * @param type      1-月份 2-年份
     * @return Date[]
     */
    private Date[] getLastRange(Date startDate, Date endDate, Integer count, Integer type){
        if (1 == type){
            LocalDate startLocalDate = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate().minusMonths(count);
            LocalDate endLocalDate = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate().minusMonths(count);

            Date start = Date.from(startLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
            Date end = Date.from(endLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());

            return new Date[]{start, end};
        }else if (2 == type){
            LocalDate startLocalDate = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate().minusYears(count);
            LocalDate endLocalDate = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate().minusYears(count);

            Date lastYearStartDate = Date.from(startLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
            Date lastYearEndDate = Date.from(endLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());

            return new Date[]{lastYearStartDate, lastYearEndDate};
        }
        return new Date[0];
    }


}
